package com.zhangln.mountbuzhou.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhangln.mountbuzhou.config.RedisConfig;
import com.zhangln.mountbuzhou.core.UserChannelRelation;
import com.zhangln.mountbuzhou.core.service.WsService;
import com.zhangln.mountbuzhou.dao.TbOnlineDao;
import com.zhangln.mountbuzhou.dao.TbPushLogDao;
import com.zhangln.mountbuzhou.dto.BaseResponse;
import com.zhangln.mountbuzhou.dto.request.PushMsgReq;
import com.zhangln.mountbuzhou.dto.ResultCode;
import com.zhangln.mountbuzhou.entity.TbOnlineEntity;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * @author sherry
 * @description
 * @date Create in 2020/4/28
 * @modified By:
 */
@Service
@Slf4j
public class PushService {

    /**
     * 推送日志
     */
    private final TbPushLogDao tbPushLogDao;
    /**
     * 在线客户端
     */
    private final TbOnlineDao tbOnlineDao;
    /**
     * WebSocket
     */
    private final WsService wsService;
    /**
     * Redis客户端
     */
    private final RedisConfig redisConfig;

    public PushService(TbPushLogDao tbPushLogDao, TbOnlineDao tbOnlineDao, WsService wsService, RedisConfig redisConfig) {
        this.tbPushLogDao = tbPushLogDao;
        this.tbOnlineDao = tbOnlineDao;
        this.wsService = wsService;
        this.redisConfig = redisConfig;
    }

    /**
     * 往指定通道推送执行消息
     * （最终所有的推送，都要调用此方法）
     *
     * @param channelId
     * @param pushMsgReq
     * @return
     */
    public BaseResponse pushMsgByChannelIdAndBody(String channelId, PushMsgReq pushMsgReq) {
        try {
//            如果当前channelId不是注册在本实例上，是无法推送的
            UserChannelRelation.get(channelId)
                    .ifPresent(channel -> {
                        log.info("执行推送  {}  \n==>\n\t\t  {}", channelId, pushMsgReq);
                        BaseResponse baseResponse = BaseResponse.builder()
                                .id(pushMsgReq.getMsgId())
                                .data(pushMsgReq.getBody())
                                .build();
                        String realResp = JSONObject.toJSONString(baseResponse);
                        channel.writeAndFlush(new TextWebSocketFrame(realResp));
//                        推送日志
                        tbPushLogDao.savePushLog(pushMsgReq.getPushId(), channelId, pushMsgReq);
//                        更新设备在线使用时间
                        tbOnlineDao.updateLastUpdatetime(channelId);
                    });
            return BaseResponse.builder().code(ResultCode.SUCCESS).build();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return BaseResponse.builder().code(ResultCode.FAILURE).build();
    }

    /**
     * 根据业务字段推送消息到指定通道
     *
     * @param pushMsgReq
     * @return
     */
    public BaseResponse pushMsg(PushMsgReq pushMsgReq) {
        try {
//            推送参数校验
            BaseResponse checkParam = checkPushParam(pushMsgReq.getPushId(), pushMsgReq.getArea()
                    , pushMsgReq.getOrgCode(), pushMsgReq.getDevice(), pushMsgReq.getUserId());
            if (!checkParam.isSuccess()) {
                log.info(String.valueOf(checkParam));
                return checkParam;
            }

            String serverInst = wsService.getInstanceFlag();
            List<TbOnlineEntity> tbOnlineEntities = tbOnlineDao.list(new QueryWrapper<TbOnlineEntity>()
                    .eq(TbOnlineEntity.SERVER_INST, serverInst)
                    .eq(StringUtils.isNotEmpty(pushMsgReq.getArea()), TbOnlineEntity.AREA, pushMsgReq.getArea())
                    .eq(StringUtils.isNotEmpty(pushMsgReq.getOrgCode()), TbOnlineEntity.ORG_CODE, pushMsgReq.getOrgCode())
                    .eq(StringUtils.isNotEmpty(pushMsgReq.getDevice()), TbOnlineEntity.DEVICE, pushMsgReq.getDevice())
                    .eq(StringUtils.isNotEmpty(pushMsgReq.getUserId()), TbOnlineEntity.USER_ID, pushMsgReq.getUserId())
            );
            log.info("请求对象：{}\n本实例 {} 本次发送客户端数量为 {} ", pushMsgReq
                    , serverInst, tbOnlineEntities.size());

            if (CollectionUtils.isEmpty(tbOnlineEntities)) {
                return new BaseResponse("本实例不存在有效客户端信息，不进行推送");
            }

            tbOnlineEntities.stream()
                    .forEach(tbOnlineEntity -> {
                        String channelId = tbOnlineEntity.getChannelId();
                        pushMsgByChannelIdAndBody(channelId, pushMsgReq);
                    });
            return BaseResponse.builder().code(ResultCode.SUCCESS).build();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return BaseResponse.builder().code(ResultCode.FAILURE).build();
    }

    public BaseResponse checkPushParam(String pushId, String area, String orgCode, String device, String userId) {
        BaseResponse checkParam = new BaseResponse("参数校验通过");
        //参数校验
        if (StringUtils.isEmpty(pushId)) {
            checkParam = BaseResponse.builder().code(ResultCode.FAILURE).message("pushId不能为空").build();
        }
        if (StringUtils.isAllEmpty(area, orgCode, device, userId)) {
            checkParam = BaseResponse.builder().code(ResultCode.FAILURE).message("请指明推送目标").build();
        }
        return checkParam;
    }

}
